local table_concat = table.concat
local io = io

---从字符串str后方寻找k
---然后k后面的字符串全部删掉
---b 为true 时 连同k一起删掉
---用于路径处理 如 C:\a\b\c\1.txt sub2('\')结果为C:\a\b\c\
function string.sub2(str, k, b)
    --反转字符串str
    local ts = string.reverse(str)
    local _, i = string.find(ts, k)--获取k在反转后的str字符串ts的位置
    if not i then
        return ''
    end
    local m = string.len(ts) - i + 1--获取k在字符串str中的位置

    --去掉寻找的字符串 k
    if b then
        b=k:len()
    else
        b = 0
    end
    return string.sub(str, 1, m-b)--返回字符串str字符k之前的部分
end

--find_r
--倒找字符串
---@param str string 原字符串
---@param k string 寻找的字符串
---@param plain bool 是否纯文本
---@return int 出现的位置 0则没有找到
function string.find_r(str, k, plain)
    --反转字符串str
    local ts = string.reverse(str)
    local i, _ = string.find(ts, k, nil, plain)--获取k在反转后的str字符串ts的位置
    if not i then
        return 0
    end
    return str:len() - (i or -1) + 1
end

--去首尾空
function string.lighter(s)
    return s:match("^[%s]*(.-)[%s]*$")
end

--分割字符串
--@param str string 完整的字符串
--@param split_char string 分隔符
--@return table 返回一个表
function string.split(str, split_char)--分割字符串
    if not(str and split_char) then return {} end
    local sub_str_tab = {}
    while true do 
        local pos,pos2 = string.find(str, split_char, 1, true) --四号参数 设为true 则作为普通文本处理 而不是模式匹配
        if not pos then
            table.insert(sub_str_tab,str)
            break
        end 
        local sub_str = string.sub(str, 1, pos - 1) 
        table.insert(sub_str_tab, sub_str)
        str = string.sub(str, pos2 + 1, string.len(str))
    end
    return sub_str_tab
end

--- 分隔字符串
---@param str string
---@param size number 每隔[size]字符切一次
---@return string
string.splitbysize = function(str, size)
    local sp = {}
    local len = string.len(str)
    if (len <= 0) then
        return sp
    end
    size = size or 1
    local i = 1
    while (i <= len) do
        table.insert(sp, string.sub(str, i, i + size - 1))
        i = i + size
    end
    return sp
end

--重复字符串
--重复str 数量number个
function string.string(str,number)
    local t = {}
    for i = 1, number do
        t[i] = str
    end
    return table_concat(t)
end

--- 进制规则
local convertChars = {
    [2] = string.splitbysize("01", 1),
    [8] = string.splitbysize("01234567", 1),
    [10] = string.splitbysize("0123456789", 1),
    [16] = string.splitbysize("0123456789ABCDEF", 1),
    [36] = string.splitbysize("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1),
}

--- 10进制数字转2/8/10/16/36进制
---@param dec number
---@param cvt number 2|8|10|16|36 默认16
---@return string
string.convert = function(dec, cvt)
    if (dec == 0) then
        return "0"
    end
    cvt = cvt or 16
    if (convertChars[cvt] == nil) then
        return "0"
    end
    local numStr = ""
    while (dec ~= 0) do
        local yu = math.floor((dec % cvt) + 1)
        numStr = convertChars[cvt][yu] .. numStr
        dec = math.floor(dec / cvt)
    end
    return numStr
end

function table.len(tb)
    local i=0
    for _, _ in pairs(tb) do
        i=i+1
    end
    return i
end

_print = print

print = function (...)
    local _arg = {...}
    local s,f={}
    for i=1,select('#',...) do
        if type(_arg[i])=='string' then
            _arg[i] = unicode.u2a(_arg[i]) or '<U2A转码失败>'
        elseif _arg[i]==nil then
            _arg[i] = '<nil>'
        end
    end
    for k,v in pairs(_arg) do
        s [k] = '_arg[' .. tostring(k) .. ']'
    end
    f = load("_print(" .. table_concat(s, ",") .. ")",nil,nil,{ _arg = _arg, _print=_print })
    f()
end

_assert = assert

assert = function (v,msg)
    _assert(v, debug.traceback( '\n' .. (unicode.u2a('===错误信息===\n'..msg) or '') ) )
end

--UTF8 => ANSI
function string.u2a(str)
    return unicode.u2a(str)
end
--ANSI => UTF8
function string.a2u(str)
    return unicode.a2u(str)
end

--创建文件夹 支持多层级
---@param path string
---@return bool
function mkdir(path)
    local sOut = io.popen('mkdir "'..path:u2a()..'" 2>nul', "r")
    local ret = sOut:read('*a'):len() == 0
    sOut:close()

    return ret
end

--判断文件是否存在 Path UTF8
---@param path string
---@return bool
function file_exist(path)
    local pipe = io.popen(
        '@if exist "' .. path:u2a() .. '" (@echo *)' ,
        'r'
    )
    local res = pipe:read("*a")
    pipe:close()

    return res:find('*',nil,true) ~= nil
end

---@param input string 要复制的文件
---@param output string 复制到哪
---@return bool
function copy(input,output)
    local command = table_concat({
        "copy",
        '/y',
        '"'..input:u2a()..'"',
        '"'..output:u2a()..'"',
        '2>nul',
    },' ')

    local sOut = io.popen(command, "r")
    local ret = sOut:read('*a'):match('%d')
    sOut:close()

    return ret ~= nil
end

---复制文件夹
function xcopy(input,output)
    local command = table_concat({
        "xcopy",
        '/y /e',
        '"'..input:u2a()..'"',
        '"'..output:u2a()..'\\"',
        '2>nul',
    },' ')
    local sOut = io.popen(command, "r")
    local data = sOut:read("*a")
    sOut:close()
    return data
end

--删文件夹
function rd(path)
    os.execute(
        ('@rd /q /s "%s" 2>nul'):format( path )
    )
end
--删文件
function delete(path)
    os.execute(
        ('del /f /q /s "%s" >nul'):format( path )
    )
end

-- 运行命令行代码
---@param command string 命令行
---@param isExecute bool os.execute 或是 io.popen(需要U2A) 根据选择可能会需要转化命令行的编码
---@return bool 是否执行成功
function runCMD(command, isExecute )
    local file
    local suc
    if isExecute then
        suc = os.execute(
           command
        )
    else
        file = io.popen(command, "r")
        if file then
            suc = true
            file:close()
        end

        
    end
    return suc
end

--移动文件
---@param source string 要移动的文件/目录
---@param destination string 目的地
---@return bool
function move(source, destination)
    local command = {
        "move",
        '/y',
        '"' .. (source:u2a() or '') .. '"',
        '"' .. (destination:u2a() or '') .. '"',
        '2>nul'
    }

    local sOut = io.popen(table_concat(command,' '), "r")
    local sData = (sOut:read("*a") or ''):a2u()
    sOut:close()
    if sData:match("%d") then
        return true
    end
    return false
end

--列出文件列表
---@param path string 目录
---@param subdirectory bool 是否包含子目录
---@param extCMD string 附加命令 /Ad 目录 /A-d 非目录 /L 小写
---@return table<int,string> 仅文件名，包含子目录的话将是完整路径
function dir_list(path , subdirectory, extCMD)
    local command = {
        'cd /d "' .. path:u2a() .. '" &&',
        "dir",
        '/b',
        (subdirectory and '/s' or ''),
        extCMD or '',
        '2>nul',
    }

    local sOut = io.popen(table_concat(command,' '), "r")
    local sData = sOut:read("*a") or ''
    sOut:close()
    return sData:sub(1,-2):split("\n")
end


function w2l(mode, input, output)
    local command = table.concat({
        "w3x2lni\\w2l.exe",
        mode,
        '"' .. input:u2a() .. '"',
        '"' .. output:u2a() .. '"',
        '2>nul',
    },' ')
    local sOut = io.popen(command, "r")
    local sData = sOut:read("*a")
    sOut:close()
    return sData
end

--mode 默认a+  读出全部数据
function read(filename, mode)
    local file = io.open(filename,mode or 'a+')
    if not file then
        return ''
    end
    local d = file:read("*a")
    file:close()
    return d
end

--w+写出
function write(filename,data)
    local file = io.open(filename,'w+')
    if not file then
        return
    end
    file:write(data)
    file:close()
end

function table_insert(tb,val)
    local c = (tb[0] or 0) + 1
    tb[0] = c
    tb[c] = val
end

function string.replace( str, s, newStr )
    local offset = newStr:len() - s:len()
    local pS,pE = str:find( s, 1, true )
    while pS do
        str = str:sub(1,pS-1) .. newStr .. str:sub( pE + 1 )

        pS,pE = str:find( s, pE + offset+1, true )
    end
    return str
end

function math.ldexp(x,y)
    return x * (2^y)
end

---@param entireString string 完整字符串
---@param callback fun(chr:string, pos:int)
function string.forEach( entireString, callback )
    assert( type(callback) == 'function', 'callback is not a function' )
    local len = entireString:len()
    local pos = 1
    local result = {}
    while pos <= len do
        local chr = entireString:sub(pos,pos)

        local opt,order1,order2 = callback( chr, pos )

        if opt == 'del' then
            if order2 then
                
            end
        elseif opt == '' then
        
        else
        end

        pos = pos + 1
    end
end

function Params2Table( ... )
    return {...}
end

---排序遍历迭代器
function xPairs( tb )
    local keys = {}
    local count = 0
    for k, v in pairs(tb) do
        count = count + 1
        keys[count] = k
    end
    table.sort(keys)
    local i = 0
    return function ()
        i = i + 1
        local k = keys[i]
        if i <= count then
            return k, tb[ k ]
        end
    end
end

base = {
    ---转化为字符串id
    sid = function ( s )
        s = s // 1 | 0
        local result = {}
        local i = 0
        local x=1
        while x ~= 0 do
            x =  s % 256 --余数
            s = ( s - x ) / 256 --下一个除数
            i = i + 1
            result [ i ] = (x .. ''):char()
        end
        result [ i ] = nil --去掉末尾0
        return table.concat(result):reverse()
    end,
    ---转化为整数id
    ---@param s string
    iid = function( s )
        assert(type(s)=='string','base.iid 传入了一个错误的参数类型')
        local id = 0
        for i=1 , s:len() do
            id = id * 256 + s:byte(i)
        end
        return id
    end,
    B2I = function (b)
        if b then
            return 1
        end
        return 0
    end,
    I2B = function (i)
        if i==0 then
            return false
        end
        return true
    end,
    ---将函数返回值保存为table
    ---例如 table = Params2Table( str:match( "(%d-),(%d)" ) ) 多个返回值存为表
    Params2Table = function ( ... )
        return {...}
    end,

}